home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / program / cpp112.zoo / src / token.c < prev    next >
C/C++ Source or Header  |  1994-07-07  |  18KB  |  794 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | token.c -- transform raw input to preprocessor tokens            |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. /*
  20.    There are (for better or worse) three interfaces to the tokenizing
  21.    mechanism, at increasing levels of abstraction.  _one_token() tokenizes
  22.    directly out of the input line buffer, and should generally only be used
  23.    while handling preprocessor directive lines.  token() pre-tokenizes an
  24.    entire line of input at a time and doles it out one token at a time.  Note
  25.    that tokens returned by token() may or may not have undergone macro
  26.    expansion; use it when you need access to pre-expanded input tokens.
  27.    exp_token() fully expands each token before returning it; this is usually
  28.    the best way to access input.
  29. */
  30.  
  31. #include <ctype.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <stddef.h>
  35. #include "global.h"
  36. #include "ztype.h"
  37. #include "alloc.h"
  38.  
  39. #define BASE10    1
  40. #define BASE8    2
  41. #define BASE16    3
  42.  
  43. #define GRANULARITY 256
  44.  
  45. extern char *next_c;
  46.  
  47. static int tok_flags = 0;
  48. static TokenP pushback_list;
  49.  
  50. /* mk_Token() -- allocate and initialize space for a Token */
  51. TokenP mk_Token()
  52. {
  53.   register TokenP T = alloc_Token();
  54.  
  55.   T->val = T->hashval = T->flags = T->type = T->subtype = 0;
  56.   T->_txt.out_of_line = T->_ws.out_of_line = NULL;
  57.   T->flags |= (INLINE_TXT | INLINE_WS);
  58.   T->_txt.inline[0] = T->_ws.inline[0] = '\0';
  59.   T->next = NULL;
  60.   return T;
  61. }
  62.  
  63. /* clear_txt() -- clear the text space of a token */
  64. void clear_txt(T)
  65.   register TokenP T;
  66. {
  67.   if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
  68.     free(T->_txt.out_of_line);
  69.   T->flags |= INLINE_TXT;
  70.   T->_txt.inline[0] = '\0';
  71. }
  72.  
  73. /* clear_ws() -- clear the white space of a token */
  74. void clear_ws(T)
  75.   register TokenP T;
  76. {
  77.   if (!(T->flags & INLINE_WS) && T->_ws.out_of_line)
  78.     free(T->_ws.out_of_line);
  79.   T->flags |= INLINE_WS;
  80.   T->_ws.inline[0] = '\0';
  81. }
  82.  
  83. /* set_txt() -- set the text of a token to |s|, copying if necessary,
  84.    and deleting the current text, if any */
  85. void set_txt(T, s)
  86.   register TokenP T;
  87.   register char *s;
  88. {
  89.   if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
  90.     free(T->_txt.out_of_line);
  91.   if (strlen(s) <= 7) {
  92.     T->flags |= INLINE_TXT;
  93.     strcpy(T->_txt.inline, s);
  94.   } else {
  95.     T->flags &= ~INLINE_TXT;
  96.     T->_txt.out_of_line = strdup(s);
  97.   }
  98. }
  99.  
  100. /* set_txt_n() -- set the text of a token to the first |n| characters
  101.    of |s|, copying if necessary, and deleting the current text, if any */
  102. void set_txt_n(T, s, n)
  103.   register TokenP T;
  104.   register char *s;
  105.   int n;
  106. {
  107.   if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
  108.     free(T->_txt.out_of_line);
  109.   if (n <= 7) {
  110.     T->flags |= INLINE_TXT;
  111.     strncpy(T->_txt.inline, s, n);
  112.     T->_txt.inline[n] = '\0';
  113.   } else {
  114.     T->flags &= ~INLINE_TXT;
  115.     T->_txt.out_of_line = mallok(n + 1);
  116.     strncpy(T->_txt.out_of_line, s, n);
  117.     T->_txt.out_of_line[n] = '\0';
  118.   }
  119. }
  120.  
  121. /* set_ws() -- set the white space of a token to |s|, copying if
  122.    necessary, and deleting the current white space, if any */
  123. void set_ws(T, s)
  124.   register TokenP T;
  125.   register char *s;
  126. {
  127.   if (!(T->flags & INLINE_WS) && T->_ws.out_of_line)
  128.     free(T->_ws.out_of_line);
  129.   if (strlen(s) <= 3) {
  130.     T->flags |= INLINE_WS;
  131.     strcpy(T->_ws.inline, s);
  132.   } else {
  133.     T->flags &= ~INLINE_WS;
  134.     T->_ws.out_of_line = strdup(s);
  135.   }
  136. }
  137.  
  138. /* free_token() -- return an allocated Token to the free list */
  139. void free_token(T)
  140.   register TokenP T;
  141. {
  142.   T->next = NULL;
  143.   free_tlist(T);
  144. }
  145.  
  146. /* free_tlist() -- return a list of Token's to the free list */
  147. void free_tlist(T)
  148.   register TokenP T;
  149. {
  150.   register TokenP T1;
  151.  
  152.   for (T1 = T; T; T = T1) {
  153.     T1 = T->next;
  154.     clear_txt(T);
  155.     clear_ws(T);
  156. #if 0
  157.     T->next = next_free_tok;
  158.     next_free_tok = T;
  159. #else
  160.     dealloc_Token(T);
  161. #endif
  162.   }
  163. }
  164.  
  165. /*
  166.    copy_token() -- return a new Token that is a duplicate of the given token
  167. */
  168. TokenP copy_token(T1)
  169.   register TokenP T1;
  170. {
  171.   register TokenP T2 = mk_Token();
  172.  
  173.   *T2 = *T1;
  174.   if (!(T1->flags & INLINE_WS))
  175.     T2->_ws.out_of_line = strdup(T1->_ws.out_of_line);
  176.   if (!(T1->flags & INLINE_TXT))
  177.     T2->_txt.out_of_line = strdup(T1->_txt.out_of_line);
  178.   T2->next = NULL;
  179.   return T2;
  180. }
  181.  
  182. /* copy_tlist() -- create a duplicate of a list of Token's */
  183. TokenP copy_tlist(T1)
  184.   register TokenP T1;
  185. {
  186.   Token head;
  187.   register TokenP T2 = &head;
  188.  
  189.   for (T2->next = NULL; T1; T1 = T1->next, T2 = T2->next)
  190.     T2->next = copy_token(T1);
  191.   return head.next;
  192. }
  193.  
  194. /* tok_shutdown() -- free all space allocated for Token's */
  195. void tok_shutdown()
  196. {
  197. #ifdef DEBUG        /* explicitly clean up, to check for memory leaks */
  198. #if 0
  199.   register TokenP T, T1;
  200.   register int i;
  201.  
  202.   for (T1 = T = tok_blocks; T; T = T1) {
  203.     T1 = T->next;
  204.     for (i = 1; i < GRANULARITY; i++) {
  205.       if (T[i].flags & IN_USE) {
  206.     fprintf(stderr, "@@@ Token not freed:  ");
  207.     dump_token(&T[i]);
  208.     fputc('\n', stderr);
  209.       }
  210.       clear_txt(&T[i]);
  211.       clear_ws(&T[i]);
  212.     }
  213.     free(T);
  214.   }
  215.   fprintf(stderr, "%d total blocks allocated\n", num_blocks);
  216. #else /* 0 */
  217.   cleanup_Token();
  218. #endif /* 0 */
  219. #endif
  220. }
  221.  
  222. /*
  223.    push_tlist() -- "un-read" the list of Token's |T|; token() will return all
  224.    of these tokens in order before reading another token from the input file
  225. */
  226. void push_tlist(T)
  227.   register TokenP T;
  228. {
  229.   register TokenP t;
  230.  
  231.   if (!T)
  232.     return;
  233.   t = T;
  234.   while (t->next)
  235.     t = t->next;
  236.   t->next = pushback_list;
  237.   pushback_list = T;
  238. }
  239.  
  240. /* mk_eof() -- makes and returns an EOF_ token */
  241. static TokenP mk_eof()
  242. {
  243.   register TokenP T = mk_Token();
  244.  
  245.   T->type = EOF_;
  246.   T->flags |= INLINE_TXT | INLINE_WS;
  247.   T->_ws.inline[0] = T->_txt.inline[0] = '\0';
  248.   return T;
  249. }
  250.  
  251. /*
  252.    mk_stopper() -- makes and returns a STOP token.  See expand_tlist() for
  253.    further information.
  254. */
  255. TokenP mk_stopper()
  256. {
  257.   register TokenP T = mk_Token();
  258.  
  259.   T->type = STOP;
  260.   T->flags |= INLINE_TXT | INLINE_WS;
  261.   T->_ws.inline[0] = T->_txt.inline[0] = '\0';
  262.   return T;
  263. }
  264.  
  265. /*
  266.    mk_unmarker() -- makes and returns a special token that informs the
  267.    tokenizer to unmark the macro text associated with token |T|.  See
  268.    expand() for further information.
  269. */
  270. TokenP mk_unmarker(T)
  271.   register TokenP T;
  272. {
  273.   register TokenP T1 = copy_token(T);
  274.  
  275.   T1->type = UNMARK;
  276.   T->flags |= INLINE_TXT | INLINE_WS;
  277.   T->_ws.inline[0] = T->_txt.inline[0] = '\0';
  278.   return T1;
  279. }
  280.  
  281. /*
  282.    mk_printable() -- makes and returns an untyped token with an
  283.    arbitrary text body, for purposes of printing directly via
  284.    print_token().
  285. */
  286.  
  287. TokenP mk_printable(s)
  288.   const char *s;
  289. {
  290.   register TokenP T = mk_Token();
  291.  
  292.   T->type = DONT_CARE;
  293.   set_ws(T, " ");
  294.   set_txt(T, s);
  295.   return T;
  296. }
  297.  
  298. /* flush_tokenizer() -- discard all Tokens pushed back by push_tlist() */
  299. void flush_tokenizer()
  300. {
  301.   free_tlist(pushback_list);
  302.   pushback_list = NULL;
  303. }
  304.  
  305. /*
  306.    number() -- copies from |s| into the token |T| a string of characters
  307.    denoting an integer or floating-point constant.  Returns a pointer to the
  308.    first uncopied character.
  309. */
  310. static char *number(s, T)
  311.   register char *s;
  312.   register TokenP T;
  313. {
  314.   int numtype = BASE10, fpflag = 0;
  315.   char *t;
  316.  
  317.   T->type = NUMBER;
  318.   if (*s == '0') {
  319.     /* check for octal or hexadecimal constant */
  320.     if ((s[1] == 'x' || s[1] == 'X') && isxdigit(s[2])) {
  321.